#include "eigen_sparse_matrix.h"


Eigen_Sparse_Matrix::Eigen_Sparse_Matrix(const string& filename)
{
	ifstream csv_matrix(filename, ios::in);
	if (!csv_matrix.is_open())
	{
		throw std::runtime_error("File opening failure ! ");
	}
	string line;            //  每次读入一行数据，存储到line字符串中
	size_t temp_row = 0;	// 记录当前的行数
	vector<double> row;     //  存放每一行除“,”外的数据元素

	// 获取文件中矩阵（方阵）的行数
	size_t counts = 0;
	while (getline(csv_matrix, line))
	{
		counts++;
	}
	this->sparse_matrix.resize(counts, counts);
	csv_matrix.clear();  			//  清除文件流上的错误标志（如 failbit、eofbit 或 badbit）。当文件流遇到错误或到达文件末尾（EOF）时，这些标志会被设置，阻止进一步的读取操作
	csv_matrix.seekg(0, ios::beg);	// 	设置输入文件流位置；0：从文件的开头开始计算位置

	// 将csv文件中的矩阵数据写入sparse_matrix
	while (getline(csv_matrix, line))
	{
		size_t pos = 0;
		string token;
		while ((pos = line.find(",")) != std::string::npos)
		{
			token = line.substr(0, pos);        //从字符串line中提取从索引位置0开始，直到索引位置pos之前的子字符串
			row.push_back(stod(token));         //stod(token):将字符串转换为double类型
			line.erase(0, pos + 1);
		}
		row.push_back(stod(line));				// 处理CSV行中的最后一个元素，这个元素后面通常没有逗号 , 作为分隔符

		for (size_t i = 0; i < row.size(); i++)
		{
			if (row[i] != 0)
			{
				this->sparse_matrix.insert(temp_row, i) = row[i];
			}
		}
		row.clear();										// 清空row以便下一行数据的读取
		temp_row++;
	}
	csv_matrix.close();

	// 完成矩阵的构造  
	sparse_matrix.makeCompressed();			// 优化存储
}


Eigen_Sparse_Matrix::Eigen_Sparse_Matrix(const string& filename, bool directed, bool renumbering)
{
	ifstream finput(filename, ios::in);
	if (!finput.is_open())
	{
		throw std::runtime_error("File opening failure ! ");
	}

	vector<size_t> src_tar(2, 0);				// 存储source 和 target
	size_t  V = 0, edge_number = 0;
	double weight = 0.;							// 提供默认值，以防文件中缺少weight列

	string line;

	// 读取方阵的元素数
	getline(finput, line); // 读取并丢弃表头 
	while (getline(finput, line))
	{
		std::istringstream iss(line);
		char comma; // 用于捕获逗号字符  
		if (!(iss >> src_tar[0] >> comma && comma == ',' && iss >> src_tar[1]))
		{
			throw std::runtime_error("Error parsing line");
		}
		V = std::max(V, std::max(src_tar[0], src_tar[1]));
		//cout<< edge_number<<endl;
		edge_number++;
	}

	// 初始化稀疏矩阵
	sparse_matrix.resize(renumbering ? V : V + 1, renumbering ? V : V + 1);

	finput.clear();  			//  清除文件流上的错误标志（如 failbit、eofbit 或 badbit）。当文件流遇到错误或到达文件末尾（EOF）时，这些标志会被设置，阻止进一步的读取操作
	finput.seekg(0, ios::beg);

	getline(finput, line); // 读取并丢弃表头 
	while (getline(finput, line))
	{
		std::istringstream iss(line);
		char comma; 		// 用于捕获逗号字符 

		// 读取line中数据
		iss >> src_tar[0] >> comma && comma == ',' && iss >> src_tar[1] >> comma && comma == ',' && iss >> weight;

		int s = renumbering ? src_tar[0] - 1 : src_tar[0];
		int d = renumbering ? src_tar[1] - 1 : src_tar[1];
		if (directed)
		{
			sparse_matrix.insert(s, d) = (weight ? weight : 1.);
		}
		else
		{
			sparse_matrix.insert(s, d) = (weight ? weight : 1.);
			sparse_matrix.insert(d, s) = (weight ? weight : 1.);
		}
	}
	finput.close();

	// 完成矩阵的构造  
	sparse_matrix.makeCompressed();
}



Eigen_Sparse_Matrix::Eigen_Sparse_Matrix(const Eigen_Sparse_Matrix& ei_spar_matrix)
{
	this->sparse_matrix = ei_spar_matrix.sparse_matrix;
}



vector<vector<pair<unsigned int, double>>> Eigen_Sparse_Matrix::sparse_matrix_to_undirected_edgelist(void)
{
	vector<vector<pair<unsigned int, double>>> edgelist;
	edgelist.resize(this->sparse_matrix.rows());					// 用m_row初始化节点数
	// 将csr中的非0元素赋值到edgelist中
	for (size_t row = 0; row < this->sparse_matrix.rows(); row++)
	{
		for (size_t col = row + 1; col < this->sparse_matrix.rows(); col++)
		{
			if (this->sparse_matrix.coeff(row, col) != 0)		// eigen 中的 sparse matrix使用coeff()读取元素
			{
				edgelist[row].push_back(make_pair(col, this->sparse_matrix.coeff(row, col)));
			}
		}
	}
	return edgelist;
}


vector<vector<double>> Eigen_Sparse_Matrix::sparse_matrix_to_matrix(void)
{
	// 获取矩阵尺寸
	int row = this->sparse_matrix.rows();
	int col = this->sparse_matrix.cols();

	// 开辟矩阵的内存，并将其元素值赋值为0
	vector<vector<double>> matrix(row, vector<double>(col, 0.));

	// 使用Eigen的稀疏矩阵迭代器来遍历非零元素  	
	for (int row = 0; row < sparse_matrix.outerSize(); row++)								// 行优先返回矩阵行数
	{
		for (Eigen::SparseMatrix<double, Eigen::RowMajor>::InnerIterator it(sparse_matrix, row); it; ++it)   // 内层迭代
		{
			matrix[it.row()][it.col()] = it.value();
		}
	}

	return matrix;
}


vector<vector<pair<unsigned int, double>>> Eigen_Sparse_Matrix::sparse_matrix_to_edgelist(bool write)
{
	vector<vector<pair<unsigned int, double>>> edgelist;
	edgelist.resize(this->sparse_matrix.rows());					// 初始化节点数

	if (write)
	{
		ofstream outfile("edgelist.csv");
		if (!outfile.is_open())
		{
			// 处理文件打开失败的情况  
			throw std::runtime_error("File opening failure ! ");
		}

		for (int row = 0; row < sparse_matrix.outerSize(); row++)							// 行优先返回矩阵行数
		{
			for (Eigen::SparseMatrix<double, Eigen::RowMajor>::InnerIterator it(sparse_matrix, row); it; ++it)	// 内层迭代
			{
				outfile << it.row() << ',' << it.col() << ',' << it.value() << '\n';
			}
		}
		outfile.close();
	}

	// 将稀疏矩阵中的非0元素赋值到edgelist中
	for (int out = 0; out < sparse_matrix.outerSize(); out++)								// 二维矩阵外层迭代
	{
		for (Eigen::SparseMatrix<double, Eigen::RowMajor>::InnerIterator it(sparse_matrix, out); it; ++it)
		{
			edgelist[it.row()].push_back(make_pair(it.col(), it.value()));// 内层迭代
		}
	}
	return edgelist;
}


	// 只保留非零元素
void Eigen_Sparse_Matrix::clear_zero(void)
{
	vector<Eigen::Triplet<double>, Eigen::aligned_allocator<Eigen::Triplet<double>>> tripletList;
	for (int i = 0; i < this->sparse_matrix.rows(); ++i)
	{
		for (int j = 0; j < this->sparse_matrix.cols(); ++j)
		{
			double value = this->sparse_matrix.coeff(i, j);
			if (value != 0.0)
			{
				tripletList.emplace_back(i, j, value);
			}
		}
	}
	this->sparse_matrix.setZero();
	this->sparse_matrix.setFromTriplets(tripletList.begin(), tripletList.end());
}




	// 设计结构矩阵交换行列
void Eigen_Sparse_Matrix::exchange(const int& row1, const int& row2)
{
	// 方式一：利用稠密矩阵，但当矩阵过大时，稠密矩阵抛出异常：内存分配失败
	// Eigen::MatrixXd swap_densematrix(this->sparse_matrix.rows(), this->sparse_matrix.cols());				
	// swap_densematrix = this->sparse_matrix.toDense();

	// swap_densematrix.row(row1).swap(swap_densematrix.row(row2));	// 交换行

	// swap_densematrix.col(row1).swap(swap_densematrix.col(row2));	// 交换列


	// vector<Eigen::Triplet<double>, Eigen::aligned_allocator<Eigen::Triplet<double>>> tripletList;  
	// for (int i = 0; i < swap_densematrix.rows(); ++i) 
	// {  
	//     for (int j = 0; j < swap_densematrix.cols(); ++j) 
	// 	{  
	//         if (swap_densematrix(i, j) != 0.0) 
	// 		{  
	//             tripletList.emplace_back(i, j, swap_densematrix(i, j));  
	//         }  
	//     }  
	// }  
	// this->sparse_matrix.setFromTriplets(tripletList.begin(), tripletList.end());  		


	// 方式二
	// 交换行
	//Eigen::SparseMatrix<double, Eigen::RowMajor> copy_sparse_matrix_col(this->sparse_matrix);
	for (int i = 0; i < this->sparse_matrix.cols(); i++)
	{
		double value_row1 = this->sparse_matrix.coeff(row1, i);
		double value_row2 = this->sparse_matrix.coeff(row2, i);
		if (value_row1 == 0.0 && value_row2 == 0.0)
		{
			continue;
		}
		else
		{
			this->sparse_matrix.coeffRef(row1, i) = value_row2;
			this->sparse_matrix.coeffRef(row2, i) = value_row1;
		}
	}

	// 交换列
	//Eigen::SparseMatrix<double, Eigen::RowMajor> copy_sparse_matrix_row(this->sparse_matrix);
	for (int i = 0; i < this->sparse_matrix.rows(); i++)
	{
		double value_col1 = this->sparse_matrix.coeff(i, row1);
		double value_col2 = this->sparse_matrix.coeff(i, row2);
		if (value_col1 == 0.0 && value_col2 == 0.0)
		{
			continue;
		}
		else
		{
			this->sparse_matrix.coeffRef(i, row1) = value_col2;
			this->sparse_matrix.coeffRef(i, row2) = value_col1;
		}
	}
}


	// 设计结构矩阵上(下)移动某一行
void Eigen_Sparse_Matrix::move(const int& init_row, const int& target_row)
{
	exchange(init_row, target_row);
	if (init_row < target_row)					// 下移
	{
		for (int i = init_row; i < target_row - 1; i++)
		{
			exchange(i, i + 1);
		}
	}
	else if (init_row > target_row)				// 上移
	{
		for (int j = init_row; j > target_row + 1; j--)
		{
			exchange(j, j - 1);
		}
	}
}

	// 根据给定的序列重新排序设计结构矩阵
vector<unsigned int> Eigen_Sparse_Matrix::arrange(map<unsigned int, vector<unsigned int>>& partition_result)
{
	vector<unsigned int>    sequence;
	vector<unsigned int>    new_sequence;
	int 					targetRow = 0;

	for (const auto& pair : partition_result)
	{
		const vector<unsigned int>& module = pair.second;		// 获取每个模块内的节点
		sequence.insert(sequence.end(), module.begin(), module.end());		// 将每个模块内的节点放入同一个序列中
	}

	// 创建matrix_seq来实时记录矩阵行列的变化
	map<int, int> index_map;
	for (int i = 0; i < sequence.size(); i++)
	{
		index_map[i] = i;		// 记录每个节点当前所在行
	}

	for (int i = 0; i < sequence.size(); i++)
	{
		if (i == index_map[sequence[i]])
		{
			continue;
		}
		exchange(i, index_map[sequence[i]]);
		for (const auto& pair : index_map)
		{
			if (pair.second == i)
			{
				int key = pair.first;
				index_map[key] = index_map[sequence[i]];
				break;
			}
		}
		index_map[sequence[i]] = i;
	}
	clear_zero();
	this->sparse_matrix.makeCompressed();
	return sequence;
}



vector<unsigned int> Eigen_Sparse_Matrix::rewrite_to_arrange_matrix(const map<unsigned int, vector<unsigned int>>& partition_result)
{
	vector<unsigned int> sequence;
	for (const auto& pair : partition_result)
	{
		const vector<unsigned int>& module = pair.second;			   // 获取每个模块内的节点
		sequence.insert(sequence.end(), module.begin(), module.end()); // 将每个模块内的节点放入同一个序列中
	}


	vector<Eigen::Triplet<double>, Eigen::aligned_allocator<Eigen::Triplet<double>>> tripletList;
	for (int i = 0; i < sparse_matrix.cols(); i++)
	{
		for (int j = 0; j < sparse_matrix.rows(); j++)
		{
			double weight = this->sparse_matrix.coeff(sequence[i], sequence[j]);
			if (weight != 0)
			{
				tripletList.emplace_back(i, j, weight);
			}
		}
	}

	this->sparse_matrix.setZero();
	this->sparse_matrix.setFromTriplets(tripletList.begin(), tripletList.end());
	return sequence;
}



void Eigen_Sparse_Matrix::write_adjmatrix(const vector<unsigned int>& order)
{
	ofstream outfile("matrix.csv");

	// 向csv文件的第一行写入节点序号
	for (int t = 0; t < order.size(); t++)
	{
		if (t == (order.size() - 1))
		{
			outfile << order[t] + 1 << "\n";
		}
		else
		{
			outfile << order[t] + 1 << ',';
		}
	}

	// 从第二行开始，向csv文件写入矩阵元素
	for (int i = 0; i < sparse_matrix.rows(); i++)
	{
		for (int j = 0; j < sparse_matrix.cols(); j++)
		{
			if (j == (sparse_matrix.cols() - 1))			// 是否为每一行的最后一个元素
			{
				if (i == j)
				{
					outfile << 1 << "\n";	// 最后一行最后一个元素
				}
				else
				{
					outfile << this->sparse_matrix.coeff(i, j) << "\n";
					//if (this->sparse_matrix.coeff(i, j) != 0)
					//{
					//	outfile << 1 << "\n";
					//}
					//else
					//{
					//	outfile << 0 << "\n";
					//}

				}
			}
			else if (i == j)
			{
				outfile << 1 << ',';
			}
			else
			{
				outfile << this->sparse_matrix.coeff(i, j) << ',';
				//if (this->sparse_matrix.coeff(i, j) != 0)
				//{
				//	outfile << 1 << ",";
				//}
				//else
				//{
				//	outfile << 0 << ",";
				//}
			}
		}
	}
	outfile.close();
}




void Eigen_Sparse_Matrix::CV_plot(void)
{
	int rows = 480;
	int cols = 640;

	cv::Mat heatmapImage(rows, cols, CV_8UC1, cv::Scalar::all(0));

	// 由于稀疏矩阵可能只包含少数非零元素，我们需要通过某种方式（如插值）来填充整个图像
	// 这里为了简单起见，我们使用最近邻插值（实际上这并不是真正的插值，而是直接赋值）
	// 注意：这种方法在稀疏点很少时会导致图像看起来很不平滑
	for (int row = 0; row < sparse_matrix.outerSize(); row++)								// 行优先返回矩阵行数
	{
		for (Eigen::SparseMatrix<double, Eigen::RowMajor>::InnerIterator it(sparse_matrix, row); it; ++it)   // 内层迭代
		{
			int row = (it.row() * 480) / this->sparse_matrix.rows();
			int col = (it.col() * 640) / this->sparse_matrix.rows();
			double value = 100.0;
			// 将热度值线性映射到0-255范围内
			uchar heatValue = static_cast<uchar>(255.0 * value / 100.0); // 假设热度值的范围是0到100

			// 直接设置对应像素的值（最近邻“插值”）
			heatmapImage.at<uchar>(row, col) = heatValue;
		}
	}

	// 为了更好的可视化效果，我们可以对图像进行一些平滑处理（如高斯模糊）
	//cv::GaussianBlur(heatmapImage, heatmapImage, cv::Size(5, 5), 0);
	cv::rectangle(heatmapImage, cv::Point(0, 0), cv::Point(cols - 1, rows - 1), cv::Scalar(255, 255, 255), 3); // 添加白色边框
	std::string title = "Heatmap of Sparse Matrix";

	cv::imshow("heatmap image", heatmapImage);
	cv::waitKey();
}






void Eigen_Sparse_Matrix::print_sparse_matrix(void)
{
	if (!sparse_matrix.nonZeros())
	{
		cerr << "There are no non-zero elements in sparse matrix ！！\n";
	}
	else
	{
		for (int outer = 0; outer < this->sparse_matrix.outerSize(); outer++)
		{
			for (Eigen::SparseMatrix<double, Eigen::RowMajor>::InnerIterator it(sparse_matrix, outer); it; ++it)
			{
				int row = it.row();
				int col = it.col();
				double value = it.value();
				cout << "Matrix coordinates(" << it.row() << "," << it.col() << ") : " << it.value() << endl;
			}
		}
	}
}

// vector<pair<unsigned int, double>> Eigen_Sparse_Matrix::get_link_outweight(const unsigned int& node)
// {
// 	// 判断节点索引是否正确
// 	if ((node < 0) && (node > sparse_matrix.rows()))
// 	{
// 		throw std::runtime_error("Error!! please check node > 0 or node < sparse_matrix.rows()! ");
// 	}

// 	vector<pair<unsigned int, double>> link_weight;

// 	for (Eigen::SparseMatrix<double, Eigen::RowMajor>::InnerIterator it(sparse_matrix, node); it; ++it) 
// 	{  
//     	link_weight.push_back(make_pair(it.col(), it.value()));  
// 	}
// 	return link_weight;
// }